package org.oslims.server.service.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import net.sf.gilead.gwt.GwtConfigurationHelper;
import net.sf.gilead.gwt.PersistentRemoteService;

import org.hibernate.Session;
import org.oslims.client.service.AnalysisService;
import org.oslims.domain.Analysis;
import org.oslims.domain.SampleType;
import org.oslims.server.dao.AnalysisDao;
import org.oslims.server.dao.SampleTypeDao;
import org.oslims.server.dao.hbm.HbmAnalysisDao;
import org.oslims.server.dao.hbm.HbmSampleTypeDao;
import org.oslims.server.dao.util.HibernateUtil;

import com.google.gwt.validation.client.InvalidConstraint;
import com.google.gwt.validation.client.interfaces.IValidator;
import com.google.gwt.validation.server.ServerValidator;

public class AnalysisServiceImpl extends PersistentRemoteService implements AnalysisService {

	/**
	 * 
	 */
	private static final long serialVersionUID = -4464139023786525836L;

	AnalysisDao analysisDao;
	SampleTypeDao sampleTypeDao;

	IValidator<Analysis> analysisValidator = new ServerValidator<Analysis>();

	public AnalysisServiceImpl() {
		analysisDao = new HbmAnalysisDao();
		sampleTypeDao = new HbmSampleTypeDao();

		net.sf.gilead.core.hibernate.HibernateUtil hibernateUtil = new net.sf.gilead.core.hibernate.HibernateUtil(HibernateUtil.getSessionFactory());
		setBeanManager(GwtConfigurationHelper.initGwtStatelessBeanManager(hibernateUtil));
	}

	@Override
	public List<Analysis> getAllAnalysis() {
		Session session = HibernateUtil.getSession();
		analysisDao.setSession(session);

		List<Analysis> result = analysisDao.findAllWithParametersAndDepartment();

		session.close();

		return result;
	}

	@Override
	public void saveOrUpdateAnalysis(Analysis analysis) {

		Set<InvalidConstraint<Analysis>> violations = analysisValidator.validate(analysis);

		if (violations.size() == 0) { // Only process the entity if valid!!!
			Session session = HibernateUtil.getSession();
			session.beginTransaction();
			try {
				analysisDao.setSession(session);
				sampleTypeDao.setSession(session);

				analysisDao.makePersistent(analysis);

				for (SampleType st : sampleTypeDao.findAllWithAnalysis()) {
					if (analysis.getValidSampleTypes().contains(st) && !st.getPossibleAnalysis().contains(analysis)) {
						st.getPossibleAnalysis().add(analysis);
						sampleTypeDao.makePersistent(st);
					} else if (!analysis.getValidSampleTypes().contains(st) && st.getPossibleAnalysis().contains(analysis)) {
						st.getPossibleAnalysis().remove(analysis);
						sampleTypeDao.makePersistent(st);
					}
				}

				session.getTransaction().commit();
			} catch (RuntimeException e) {
				session.getTransaction().rollback();
				throw e;
			} finally {
				session.close();
			}
		}
	}

	@Override
	public List<Analysis> getAllAnalysis(int start, int length, String sortBy, boolean desc) {
		Session session = HibernateUtil.getSession();
		analysisDao.setSession(session);

		List<Analysis> result = analysisDao.findAllWithParametersAndDepartment(start, length, sortBy, desc);

		// Fetch Additionally the sample types (As only one association can be
		// fetched via hql at a time
		for (Analysis ar : result) {
			ar.getValidSampleTypes().size();
		}

		session.close();

		return result;
	}

	@Override
	public Integer getAnalysisCount() {
		Session session = HibernateUtil.getSession();
		analysisDao.setSession(session);

		Integer result = analysisDao.getEntityCount();

		session.close();

		return result;
	}

	@Override
	public List<Analysis> getAnalysisForSampleTypes(List<SampleType> sampleTypes) {
		Session session = HibernateUtil.getSession();
		analysisDao.setSession(session);
		sampleTypeDao.setSession(session);

		List<SampleType> newList = new ArrayList<SampleType>();

		for (SampleType st : sampleTypes) {
			newList.add(sampleTypeDao.findById(st.getId(), false));
		}

		List<Analysis> result = analysisDao.findAllForSampleTypes(newList);

		session.close();

		return result;
	}

	@Override
	public List<Analysis> getAllAnalysisByState(String state) {
		Session session = HibernateUtil.getSession();
		analysisDao.setSession(session);

		List<Analysis> result = analysisDao.findAllByStateWithParametersAndDepartment(state);

		session.close();

		return result;
	}

}
